#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/atomic.h>
#include <linux/errno.h>

static spinlock_t spinlock_test; // 定义spinlock_t类型自旋变量
static int flag = 1;
static int open_test(struct inode *inode, struct file *file)
{

    spin_lock(&spinlock_test); // 自旋枷锁
    /*  if(flag!=1){  //判断标志位flag 的值是否等于1
          spin_unlock(&spinlock_test);
          return -EBUSY;
      }
      flag=0; //将标志位的值设置为0*/
    // spin_unlock(&spinlock_test); // 自旋锁解锁
    printk("\n this is open_test \n");
    return 0;
};

static ssize_t read_test(struct file *file, char __user *ubuf, size_t len, loff_t *off)
{
    int ret;
    char kbuf[10] = "topeet"; // 定义char类型字符串变量kbuf
    printk("\nthis is read_test \n");
    ret = copy_to_user(ubuf, kbuf, strlen(kbuf)); // 使用copy_to_user接收用户空间传递的数据
    if (ret != 0)
    {
        printk("copy_to_user is error \n");
    }
    printk("copy_to_user is ok \n");
    return 0;
}
static char kbuf[10] = {0}; // 定义char类型字符串全局变量kbuf
static ssize_t write_test(struct file *file, const char __user *ubuf, size_t len, loff_t *off)
{
    int ret;
    ret = copy_from_user(kbuf, ubuf, len); // 使用copy_from_user接收用户空间传递的数据
    if (ret != 0)
    {
        printk("copy_from_user is error\n");
    }
    if (strcmp(kbuf, "topeet") == 0)
    { // 如果传递的kbuf是topeet就睡眠四秒钟
        ssleep(4);
    }
    else if (strcmp(kbuf, "itop") == 0)
    { // 如果传递的kbuf是itop就睡眠两秒钟
        ssleep(2);
    }
    printk("copy_from_user buf is %s \n", kbuf);
    return 0;
}
static int release_test(struct inode *inode, struct file *file)
{
    // printk("\nthis is release_test \n");
    // spin_lock(&spinlock_test); // 自旋锁加锁
    // flag = 1;
    spin_unlock(&spinlock_test); // 自旋锁解锁
    return 0;
}

struct chrdev_test
{
    dev_t dev_num;            // 定义dev_t类型变量来表示设备号
    int major, minor;         // 定义int 类型的主设备号和次设备号
    struct cdev cdev_test;    // 定义字符设备
    struct class *class_test; // 定义结构体变量class 类
};

struct chrdev_test dev1; // 创建chardev_test类型结构体变量

static struct file_operations fops_test = {
    .owner = THIS_MODULE,    // 将owner字段指向本模块，可以避免在模块的操作正在被使用时卸载该模块
    .open = open_test,       // 将open字段指向chrdev_open(...)函数
    .read = read_test,       // 将open字段指向chrdev_read(...)函数
    .write = write_test,     // 将open字段指向chrdev_write(...)函数
    .release = release_test, // 将open字段指向chrdev_release(...)函数
}; // 定义file_operations结构体类型的变量cdev_test_ops

static int __init chrdev_fops_init(void) // 驱动入口函数
{

    if (alloc_chrdev_region(&dev1.dev_num, 0, 1, "chrdev_name") < 0)
    {
        printk("alloc_chrdev_region is error\n");
    }
    printk("alloc_chrdev_region is ok\n");
    dev1.major = MAJOR(dev1.dev_num); // 通过MAJOR()函数进行主设备号获取
    dev1.minor = MINOR(dev1.dev_num); // 通过MINOR()函数进行次设备号获取
    printk("major is %d\n", dev1.major);
    printk("minor is %d\n", dev1.minor);

    ////使用cdev_init()函数初始化cdev_test结构体，并链接到cdev_test_ops结构体
    cdev_init(&dev1.cdev_test, &fops_test);
    dev1.cdev_test.owner = THIS_MODULE; // 将owner字段指向本模块，可以避免在模块的操作正在被使用时卸载该模块

    cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
    printk("cdev_add is ok\n");
    dev1.class_test = class_create(THIS_MODULE, "class_test");               // 使用class_create进行类的创建，类名称为class_test
    device_create(dev1.class_test, NULL, dev1.dev_num, NULL, "device_test"); // 使用device_create进行设备的创建，设备名称为device_test

    return 0;
}
static void __exit chrdev_fops_exit(void) // 驱动出口函数
{
    cdev_del(&dev1.cdev_test);                     // 使用cdev_del()函数进行字符设备的删除
    unregister_chrdev_region(dev1.dev_num, 1);     // 释放字符驱动设备号
    device_destroy(dev1.class_test, dev1.dev_num); // 删除创建的设备
    class_destroy(dev1.class_test);                // 删除创建的类
    printk("module exit \n");
}
module_init(chrdev_fops_init);    // 注册入口函数
module_exit(chrdev_fops_exit);    // 注册出口函数
MODULE_LICENSE("GPL v2");         // 同意GPL开源协议
MODULE_AUTHOR("wang fang chen "); // 作者信息
